<?php

/**
 * Singleton Request Class
 *
 * @author Ben Rowe
 */
class Request extends SingletonEnforcer
{
	/**
	 * Global Hash of request variables
	 *
	 * @access private
	 * @var array
	 */
	var $_global = array();
	
	/**
	 * Constructor
	 * This constructor MUST not be called directly!
	 *
	 * @access public
	 * @return Request
	 */
	function Request($singletonEnforcer) 
	{
		$this->_verifySingleton($singletonEnforcer); // enforce this singleton
		$this->import($_REQUEST);
		unset($_POST, $_GET, $_REQUEST);// this will force sections to use this class!
	}
	
	/**
	 * Retreives instance of this class
	 * This handles the singleton part of the object
	 *
	 * @static 
	 * @access public
	 * @return Request
	 */
	function &getInstance()
	{
		static $_instance;
		if(!$_instance) {
			$_instance = new Request(new SingletonEnforcer);
		}
		return $_instance;
	}
	
	/**
	 * Extends from the get method
	 * casts the returned value to a boolean before returning
	 *
	 * @access public
	 * @param string $key
	 * @param boolean $default
	 * @return boolean
	 */
	function getBoolean($key, $default = false)
	{
		$value = $this->get($key, $default);
		// try to detected the value type and act apon it
		if(is_bool($value)) {
			return $value;
		} elseif(is_numeric($value)) {
			return (bool)$value;
		} elseif(is_string($value)) {
			$value = strtolower(trim($value));
			if($value === 'true') {
				return true;
			} elseif($value === 'false') {
				return false;
			}
		}
		return $default;		
	}
	
	/**
	 * Extends from the get method
	 * casts the returned value to a numerical (Float) value before returning
	 * the default value is also casted to a numeric value
	 * 
	 * @access public
	 * @param string $key
	 * @param numeric $default
	 * @return float
	 */
	function getNumeric($key, $default = 0)
	{
		$value = $this->get($key, false);
		// if we actually got a value back!
		if($value != false) {
			return (float)$value;
		}
		return (float)$default;
	}
	
	/**
	 * Extends from the get method
	 * casts the returned value to an integer before returning
	 * The default value is also casted to an integer
	 *
	 * @access public
	 * @param string key
	 * @param integer $default
	 * @return integer
	 */
	function getInt($key, $default = 0)
	{
		$value = $this->get($key, false);
		if($value != false) {
			return (int)$value;
		}
		return (int)$default;
	}
	
	/**
	 * Get a key from the hash if it exists, otherwise the $default is returned
	 *
	 * @access public
	 * @param string $key
	 * @param mixed $default
	 * @return mixed
	 */
	function get($key, $default = null)
	{
		if(!$this->_checkKey($key)) return $default; // discard if the key is invalid!
		if($this->keyExists($key)) {
			return $this->_global[$key];
		}
		return $default;
	}
	
	/**
	 * Try to retrieve multiple keys from the hash, returns null for each key if they don't exists
	 * Returns in the same order as the keys were provided in.
	 *
	 * @access public
	 * @param array $keys
	 * @return array
	 */
	function getKeys($keys)
	{
		$values = array();
		foreach($keys as $key) {
			$values[$key] = $this->get($key);
		}
		return $values;
	}
	
	/**
	 * Set a key into the hash
	 * Alias of the private _add
	 * It's setup as an alias as the private interface may change in future revisions
	 *
	 * @access public
	 * @param string $key
	 * @param mixed $value
	 * @return boolean
	 */
	function set($key, $value)
	{
		return $this->_add($key, $value);
	}
	
	/**
	 * Import an array into the global hash
	 *
	 * @access public
	 * @param array $array
	 * @return boolean
	 */
	function import($array)
	{
		if(is_array($array)) {
			// we now need to loop though the array, preserving the keys
			foreach($array as $key=>$value) {
				$this->_add($key, $value);
			}
			return true;
		}
		return false;
	}
	
	/**
	 * Check that the provided key exists in the global hash
	 *
	 * @access public
	 * @param string $key
	 * @return boolean true if exists
	 */
	function keyExists($key)
	{
		if(!$this->_checkKey($key)) return false;
		
		return (array_key_exists($key, $this->_global));
	}
	
	/**
	 * Private method for adding a new key/value into the global hash
	 *
	 * @access private
	 * @param string $key (must be alpha, no numeric keys!)
	 * @param mixed $value
	 * @return boolean
	 */
	function _add($key, $value)
	{
		// quickly check to make sure the key is ok!
		if(!$this->_checkKey($key)) return false;

		// attempt to add the variable in
		if($this->_global[(string)$key] = $value) {
			return true;
		}
		// something has gone wrong and we're unable to assign the value into the hash
		return false;
	}
	
	/**
	 * Ensure that the provided key is a valid format
	 *
	 * @access private
	 * @param string $key
	 * @return boolean
	 */
	function _checkKey($key)
	{
		// ensure that the first character is a alpha character
		return (preg_match("/^([_a-z]{1})([a-z_\d]*)$/i", $key));
	}
	
	
}


?>